
#include "axis.h"

#include <QDebug>
#include <cmath>

#include "spdlog/spdlog.h"

using namespace std;

namespace qgraphic {
Axis::Axis() {
    // qDebug("[axis] width: %f, height: %f, unit: %f, precision: %f", width, height, unit, precision);
    width = 1024;
    height = 768;
    unit = 1e-6;
    precision = 1e-9;
    scale = 1;
    unit_scale = unit / precision;
    // cell 的系数，由unit / precision;
    cell_scale = 1;
    // 缩放系数;
    scale = 1;  // 1 对应 mm;
    scale_max = 500000000;
    scale_min = 0.00000038;
    // 线宽;
    line_width = 1;
    // 坐标轴偏移量;
    dx = 0;
    dy = 0;
    // matrix: [scaleX, 0, tranX, 0, scaleY, tranY, 0, 0, 1];
    // matrix = [scale, 0, dx, 0, -scale, dy, 0, 0, 1];
    // matrix = TranMatrix3x3(scale, scale, dx, dy);
    // 单位转换后的真实坐标;
    real_x = 0;
    real_y = 0;
    // 鼠标移动坐标;
    pos_x = 0;
    pos_y = 0;
    pos_real_x = 0;
    pos_real_y = 0;
    mouse_pixel_x = 0;
    mouse_pixel_y = 0;
    zero_pixel_x = 0;
    zero_pixel_y = 0;
    // 绘图坐标;
    draw_x = 0;
    draw_y = 0;
    // 吸附;
    adsorp = true;
    Point adsorp_point(0, 0);
    adsorp_precision = 1;
    // adsorp_precision = 0.001 * 100;
    // adsorp_precision = 5;

    // 网格;
    AxisGrid grid;

    // 标尺X;
    AxisRuler rulerX(width, 50);
    AxisRuler rulerY(50, height);
    // step = 0;
    // step_divid = 0;
    BBox real_box(0, 0, 0, 0);
}

Axis::~Axis() {
}
void Axis::init(int width_, int height_, double unit_, double precision_) {
    width = width_;
    height = height_;
    unit = unit_;
    precision = precision_;
}

void Axis::setCenter() {
    dx = width / 2;
    dy = height / 2;
}

/**
 * 计算网格吸附点
 * @return:number[]
 * @memberof QedaAxis
 */
Point Axis::getGridAdsorpPoint() {
    // 网格精度吸附点
    double x = real_x;
    double y = real_y;
    double p = 1000 * adsorp_precision / unit_scale;
    double x_min = std::floor(x / p);
    double x_max = std::ceil(x / p);
    double y_min = std::floor(y / p);
    double y_max = std::ceil(y / p);

    Point point(x, y);
    Point p_left_down(x_min * p, y_min * p);
    Point p_left_top(x_min * p, y_max * p);
    Point p_rigth_down(x_max * p, y_min * p);
    Point p_rigth_top(x_max * p, y_max * p);

    double d_left_down = point.distance(p_left_down);
    double d_left_top = point.distance(p_left_top);
    double d_rigth_down = point.distance(p_rigth_down);
    double d_rigth_top = point.distance(p_rigth_top);
    // min_d = min(d_left_down, d_left_top, d_rigth_down, d_rigth_top);
    double min_d = min(d_left_down, d_left_top);
    min_d = min(d_rigth_down, min_d);
    min_d = min(d_rigth_top, min_d);

    if (d_left_down == min_d)
        return p_left_down;
    if (d_left_top == min_d)
        return p_left_top;
    if (d_rigth_down == min_d)
        return p_rigth_down;
    if (d_rigth_top == min_d)
        return p_rigth_top;
    return p_left_down;
}

/**
 * 生成网格线
 * @param:
 * @return:Lines
 * @memberof QedaAxis
 */
void Axis::getGridLine() {
    // // logging.info(f'bounds:{bounds.x_min}, {bounds.x_max}, {bounds.y_min}, {bounds.y_max}')
    // // logging.info(f'bounds err:{bounds.x_max - bounds.x_min},  {bounds.y_max- bounds.y_min}')
    // // 根据缩放比例归一化宽度为整数刻度
    double w = 50;
    double s = w / scale;
    for (int i = 10; i >= 0; i--) {
        if (s > pow(10, i)) {
            s = s - (int(s) % int(pow(10, i)));
            break;
        }
        if (s < pow(0.1, i)) {
            s = pow(0.1, i);
            break;
        }
    }
    s = ceil(s);
    w = s * scale;
    // // 刻度细分梯度设计
    double gradient = 1;
    double err = width / w;
    double num = abs(bounds.x_max - bounds.x_min) / w;
    if (num < grid.num_min) {
        while (err < 10) {
            err = err * 10;
            gradient = gradient * 10;
        }
    }
    // 单个画布网格精度
    double graph_precision = w / gradient / scale;
    // 单个真实网格精度
    double grid_precision = graph_precision / unit_scale;

    // // 计算网格数量, 向上取整
    int x_left = ceil((bounds.x_min / w) * gradient);
    int x_right = ceil((bounds.x_max / w) * gradient);
    int y_left = ceil((bounds.y_min / w) * gradient);
    int y_right = ceil((bounds.y_max / w) * gradient);

    // // 计算x、y最大，最小
    double s_x_min = bounds.x_min / scale;
    double s_x_max = bounds.x_max / scale;
    double s_y_min = bounds.y_min / scale;
    double s_y_max = bounds.y_max / scale;

    // 简化运算，提前算好系数
    // 单个画布网格精度
    grid.graph_precision = graph_precision;
    // 单个真实网格精度
    grid.precision = grid_precision;
    // 左右范围
    grid.x_left = x_left;
    grid.x_right = x_right;
    grid.y_left = y_left;
    grid.y_right = y_right;

    // // 宽度
    grid.w = w;
    // // 尺子跟着动
    rulerX.w = w;
    rulerY.w = w;
    // // 画网格线
    if (grid.show) {
        for (int i = x_left; i < x_right; i++) {
            QVector<QVector2D> t;
            t.append(QVector2D(i * graph_precision, s_y_min));
            t.append(QVector2D(i * graph_precision, s_y_max));
            grid.lines.append(t);
        }
        for (int i = y_left; i < y_right; i++) {
            QVector<QVector2D> t;
            t.append(QVector2D(s_x_min, i * graph_precision));
            t.append(QVector2D(s_x_max, i * graph_precision));
            grid.lines.append(t);
        }
    }
}

// // 获取尺子X刻度和文字
void Axis::getRulerX() {
    rulerX.paths.clear();
    rulerX.texts.clear();
    double r_dx = dx;
    double r_dy = rulerX.height;
    // 缩放系数
    int left = grid.x_left;
    int right = grid.x_right;
    double s1 = grid.graph_precision * scale;
    double s2 = grid.precision;
    double step = s1;
    double step_divid = s2;

    // 判断单位刻度值是否过于大或过小，放置后面0个数太多，显示重合，需要减少数量
    // 获取线条和文字
    for (int i = left; i < right; i++) {
        double label = round(i * s2 * unit_scale * 10e6) / 10e6;
        if (i % 10 == 0) {
            QVector<double> p, t;
            p.append(r_dx + i * s1);      // x1
            p.append(r_dy);               // y1
            p.append(r_dx + i * s1);      // x2
            p.append(r_dy - 30);          // y2
            p.append(10);                 // length
            p.append(r_dx + i * s1 + 2);  // label x
            p.append(r_dy - 10);          // label y
            p.append(label);              // label
            rulerX.paths.append(p);
            // rulerX.texts.append(t);
        } else if (i % 5 == 0) {
            QVector<double> p, t;
            p.append(r_dx + i * s1);  // x1
            p.append(r_dy);           // y1
            p.append(r_dx + i * s1);  // x2
            p.append(r_dy - 20);      // y2
            p.append(5);              // length
            p.append(r_dx + i * s1 + 2);
            p.append(r_dy - 10);
            p.append(label);
            rulerX.paths.append(p);
            // rulerX.texts.append(t);
        } else {
            QVector<double> p, t;
            p.append(r_dx + i * s1);  // x1
            p.append(r_dy);           // y1
            p.append(r_dx + i * s1);  // x2
            p.append(r_dy - 10);      // y2
            p.append(1);              // length
            rulerX.paths.append(p);
        }
    }
    // real_box.x_min = left * s2
    // real_box.x_max = right * s2
}

// // 获取尺子Y刻度和文字
void Axis::getRulerY() {
    rulerY.paths.clear();
    rulerY.texts.clear();
    // 偏移
    double r_dx = rulerY.width;
    double r_dy = dy;
    // 边框
    int left = grid.y_left;
    int right = grid.y_right;
    double s1 = grid.graph_precision * scale;
    double s2 = grid.precision;

    for (int i = left; i < right; i++) {
        double label = round(i * s2 * unit_scale * 10e6) / 10e6;
        if (i % 10 == 0) {
            QVector<double> p, t;
            p.append(r_dx);           // y1
            p.append(r_dy - i * s1);  // x1
            p.append(r_dx - 30);      // y2
            p.append(r_dy - i * s1);  // x2
            p.append(10);             // length
            p.append(r_dx - 10);
            p.append(r_dy - i * s1);
            p.append(label);
            rulerY.paths.append(p);
            // rulerY.texts.append(t);
        } else if (i % 5 == 0) {
            QVector<double> p, t;
            p.append(r_dx);           // y1
            p.append(r_dy - i * s1);  // x1
            p.append(r_dx - 20);      // y2
            p.append(r_dy - i * s1);  // x2
            p.append(5);              // length
            p.append(r_dx - 10);      // y2
            p.append(r_dy - i * s1);  // x2
            p.append(label);
            rulerY.paths.append(p);
            // rulerY.texts.append(t);
        } else {
            QVector<double> p, t;
            p.append(r_dx);           // y1
            p.append(r_dy - i * s1);  // x1
            p.append(r_dx - 10);      // y2
            p.append(r_dy - i * s1);  // x2
            p.append(1);              // length
            rulerY.paths.append(p);
        }
    }
}

// 更新坐标信息
void Axis::updateValue() {
    unit_scale = unit / (precision * cell_scale);

    // 像素坐标, 转换为笛卡尔坐标系
    pos_real_x = pos_x - dx;
    pos_real_y = -(pos_y - dy);

    // 转换系数, 像素转真实坐标系数
    double factor = 1000 / scale / unit_scale;

    // 真实坐标，单位转换;
    real_x = pos_real_x * factor;
    real_y = pos_real_y * factor;

    //
    board_real_x = real_x;
    board_real_y = real_y;
    // 固定坐标精度;
    if (unit == 1.0e-2) {
        real_x = round(real_x * 10e8) / 10e8;
        real_y = round(real_y * 10e8) / 10e8;
    }
    if (unit == 1.0e-3) {
        real_x = round(real_x * 10e7) / 10e7;
        real_y = round(real_y * 10e7) / 10e7;
    }
    if (unit == 1.0e-6) {
        real_x = round(real_x * 10e4) / 10e4;
        real_y = round(real_y * 10e4) / 10e4;
    }
    if (unit == 1.0e-9) {
        real_x = round(real_x * 10) / 10;
        real_y = round(real_y * 10) / 10;
    }
    // 绘图坐标;
    draw_x = real_x / unit;
    draw_y = real_y / unit;
    // 线宽;
    line_width = 1 / scale;
    // 计算边框;
    bounds.x_min = -dx;
    bounds.y_min = -(height - dy);
    bounds.x_max = width - dx;
    bounds.y_max = dy;

    bounds_box.x_min = bounds.x_min / scale;
    bounds_box.y_min = bounds.y_min / scale;
    bounds_box.x_max = bounds.x_max / scale;
    bounds_box.y_max = bounds.y_max / scale;

    double s_unit = 1 / scale / unit_scale;
    bounds_unit.x_min = bounds.x_min * s_unit;
    bounds_unit.y_min = bounds.y_min * s_unit;
    bounds_unit.x_max = bounds.x_max * s_unit;
    bounds_unit.y_max = bounds.y_max * s_unit;

    SPDLOG_INFO("pre>>");
    SPDLOG_INFO("[axis ] scale: {}, dx: {}, dy: {}", scale, dx, dy);
    SPDLOG_INFO("[mouse pixiel ] x: {}, y: {}", mouse_pixel_x, mouse_pixel_y);
    SPDLOG_INFO("[pos pixiel ] x: {}, y: {}", pos_x, pos_y);
    SPDLOG_INFO("[real ] x: {}, y: {}", real_x, real_y);

    // 鼠标像素坐标
    mouse_pixel_x = pos_x;
    mouse_pixel_y = pos_y;

    // 原点像素坐标
    zero_pixel_x = dx;
    zero_pixel_y = dy;

    // 鼠标吸附
    if (adsorp) {
        Point ab_point = getGridAdsorpPoint();

        // 真实坐标设置为吸附点坐标
        real_x = ab_point.x;
        real_y = ab_point.y;

        // 吸附点真实坐标
        adsorp_point.x = ab_point.x;
        adsorp_point.y = ab_point.y;

        SPDLOG_INFO("[adsorp adsorp_point] x: {}, y: {}", adsorp_point.x, adsorp_point.y);
        // 鼠标像素坐标设置为吸附点坐标
        mouse_pixel_x = real_x / factor + dx;
        mouse_pixel_y = -(real_y / factor) + dy;
    }
    SPDLOG_INFO("end>>");

    // 转换矩阵
    matrix.setScale(scale, scale);
    matrix.setTranslate(dx, dy);

    Point mouse_point(round(real_x * unit_scale), round(real_y * unit_scale));

    // 鼠标盒子
    bounds_mouse.x_min = mouse_point.x - bounds_mouse_range / scale;
    bounds_mouse.y_min = mouse_point.y - bounds_mouse_range / scale;
    bounds_mouse.x_max = mouse_point.x + bounds_mouse_range / scale;
    bounds_mouse.x_max = mouse_point.y + bounds_mouse_range / scale;

    getGridLine();
    getRulerX();
    getRulerY();
}
void Axis::tranlate(float t_dx, float t_dy) {
    dx += t_dx;
    dy += t_dy;
    updateValue();
}
// // 鼠标移动事件
// void Axis::onMouseMove(QMouseEvent *e)
// {
//     static int x = 0, y = 0;
//     if(x != 0 && y !=0 )
//     {
//         dx = dx + (x - e->localPos().x());
//         dy = dy + (y - e->localPos().y());
//     }
//     x = e->localPos().x();
//     y = e->localPos().y();
// }
void Axis::onMouseMove(float x, float y) {
    // pos_x = e->x();
    // pos_y = e->y();
    pos_x = x;
    pos_y = y;
    updateValue();
}

void Axis::onMouseWheel(QWheelEvent *e) {
    int s = 2;
    if (e->angleDelta().y() < 0) {
        // qDebug("wheel up");
        if (scale >= scale_min * s) {
            dx = dx + (pos_x - dx) / s;
            dy = dy + (pos_y - dy) / s;
            scale = scale / s;
        }
    } else {
        // qDebug("wheel down");
        if (scale <= scale_max / s) {
            dx = dx - (pos_x - dx);
            dy = dy - (pos_y - dy);
            scale = scale * s;
        }
    }

    updateValue();
    // updateValue();
    // getMouseCrossLine();
    // getCenterCrossLine();
}
}  // namespace qgraphic